package com.cyy.operation.appium;

import io.appium.java_client.android.nativekey.AndroidKey;
import lombok.extern.slf4j.Slf4j;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

// andriod的adb相关的命令
@Slf4j
public abstract class AbstractADB {

    public abstract String get_package(String path);

    public abstract String get_versionCode(String apkpath);

    public abstract String get_versionName(String apkpath);

    public abstract String get_activity(String apkpath);

    public abstract void keyevent(AndroidKey keycode, String series);

    /**
     * 打电话
     * @param series 设备的序列号
     * @param tel 要拨打的电话号码
     * @return
     */
    public abstract boolean call_phone(String series,String tel);

    /**
     * 挂电话
     * @param series 设备序列号
     * @return
     */
    public abstract void cancel_phone(String series);

    /**
     * 发送短信
     * @param series 设备的序列号
     * @param tel 要发送给谁的手机号码
     * @param msg 短信内容
     */
    public abstract void send_message(String series, String tel,String msg);

    public String remove_file(String fpath, String series) {
        return exeadb("shell rm " + fpath, series);
    }

    public String remove_dir(String dirpath, String series) {
        return exeadb("shell rm -r " + dirpath, series);
    }

    public void sleep(int mills) {
        try {
            Thread.sleep(mills);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }

    /**
     * 判断指定程序是否安装
     *
     * @param pkg    程序的包名字
     * @param series 执行机的包名字
     * @return 如果安装则返回true, 否则返回false
     */
    public boolean is_app_installed(String pkg, String series) {
        String exeadb = exeadb("shell pm list packages -s|findstr " + pkg, series).replace("\n", "");
        return !exeadb.equals("");
    }

    /**
     * 卸载指定的程序
     *
     * @param pkg    包名字
     * @param series
     * @return 卸载成功返回true, 否则返回false
     */
    public boolean uninstall_apk(String pkg, String series) {
        String exeadb = exeadb("uninstll " + pkg, series).replace("\n", "");
        return exeadb.equals("Success");
    }

    /**
     * 在指定执行机上运行 adb shell dumpsys battery,获取电池的信息
     * adb -s d51ad9ff shell 当多台执行机并行时，指定执行机
     * 相关参数介绍:
     * status: 1            #电池状态：2：充电状态 ，其他数字为非充电状态
     * health: 2            #电池健康状态：只有数字2表示good
     * present: true        #电池是否安装在机身
     * level: 55            #电量: 百分比
     * voltage: 3977         #电池电压
     * current now: -335232  #电流值，负数表示正在充电
     * temperature: 335      #电池温度，单位是0.1摄氏度
     * technology: Li-poly    #电池种类=
     *
     * @param series 执行机的序列号
     * @return 执行命令后的打印信息
     */
    public String get_battery_info(String series) {
        return this.exeadb("shell dumpsys battery", series);
    }

    /**
     * 获取当前连接的设备
     *
     * @return
     */
    public String get_advice(String series) {
        return exeadb(String.format("devices|findstr %s.*device", series), null);
    }

    /**
     * 连接指定设备,连接成功，返回true，否则返回false
     *
     * @param series
     */
    public boolean connect_advice(String series) {
        String conn = exeadb("connect " + series, null).replace("\n", "");
        return conn.contains("connected to " + series);
    }

    /**
     * 熄灭屏幕,power,如果屏幕在唤醒状态，则操作会关闭熄灭屏幕，否则则唤醒屏幕
     *
     * @param series 执行机的序列号
     * @return
     */
    public String awake(String series) {
        return exeadb("shell input keyevent 26", series);
    }

    /**
     * 获取手机系统版本
     *
     * @param series
     * @return
     */
    public String get_platform_version(String series) {
        return exeadb("shell getprop ro.build.version.release", series);
    }

    /**
     * 获取手机的厂商名字
     *
     * @param series
     * @return
     */
    public String get_brand(String series) {
        return exeadb("shell getprop ro.product.brand", series);
    }

    /**
     * 获取手机设备型号: eg: PCAM00
     *
     * @param series
     * @return
     */
    public String get_model(String series) {
        return exeadb("shell getprop ro.product.model", series);
    }

    /**
     * 屏幕是否为锁屏
     *
     * @param series
     * @return 如果屏幕处于解锁状态则返回true，否则返回false
     */
    public boolean is_awake(String series) {
        String mIsShowing = exeadb("shell dumpsys window policy | findstr \"mAwake=\"", series);
        assert mIsShowing != null;
        if (mIsShowing.contains("mAwake=true")) {
            return true;
        }
        return false;
    }

    /**
     * 屏幕是否解锁状态
     *
     * @param series 执行机的序列号，则表示只有一台执行机，可以传空
     * @return 解锁:true
     */
    public boolean is_screen_lock(String series) {
        String isshow = exeadb("shell dumpsys window policy | findstr \"mIsShowing\"", series);
        if (isshow.equals("mIsShowing=false")) return true;
        return false;
    }

    /**
     * 获取整个设别的电量消耗信息 adb shell dumpsys batterystats
     *
     * @param series 指定手机的序列号
     * @return 执行命令后的打印信息
     */
    public String get_battery_more(String series) {
        return this.exeadb("shell dumpsys batterystats|more +10", series);
    }

    /**
     * 获取手机的总内存
     *
     * @param series 执行机的序列号
     * @return
     * @throws Exception
     */
    public String getMemTotal(String series) {
        return this.exeadb("shell cat /proc/meminfo |findstr MemTotal", series);
    }

    public String getMemFree(String series) {
        return this.exeadb("shell cat /proc/meminfo |findstr MemFree", series);
    }

    /**
     * 获取 Virtual Set Size 虚拟耗用内存（包含共享库占用的内存），和 Resident Set Size 实际使用物理内存（包含共享库占用的内存）
     *
     * @return
     */
    public List<Map<String, String>> getVssAndRss(String series, String pkg) {
        List<Map<String, String>> maps = new ArrayList<>();
        String vrss = this.exeadb(String.format("shell top -n 1 |findstr \"%s\"", pkg), series);
        String[] rownames = {"PID", "USER", "PR", "NI", "VIRT", "RES", "SHR", "S[%CPU]", "%MEM", "TIME+", "ARGS", "?[0m"};
        String[] vrsss = vrss.split("\n");
        for (int i = 0; i < vrsss.length; i++) {
            String onevr = vrsss[i];
            String[] split = onevr.split("\\s+");
            Map<String, String> onevr_map = new HashMap<>();
            for (int i1 = 0; i1 < split.length; i1++) {
                onevr_map.put(rownames[i1], split[i1]);
            }
            maps.add(onevr_map);
        }

        return maps;
    }


    /**
     * 获取指定apk的电量消耗信息
     *
     * @param series 执行机的序列号
     * @param pkg    包名称
     * @return 执行打印信息
     * @throws Exception
     */
    public String get_battery_package(String series, String pkg) {
        return this.exeadb("shell dumpsys batterystats " + pkg, null);
    }

    /**
     * 获取 Proportional Set Size 实际使用的物理内存（比例分配共享库占用的内存）
     *
     * @param series
     * @param pkg
     * @return
     * @throws Exception
     */
    public String getPSS(String series, String pkg) {
        return this.exeadb("shell dumpsys meminfo " + pkg, series);
    }

    public String connect_mobile(String series) throws Exception {
        return this.exeadb("connect " + series, null);
    }

    /**
     * 截屏
     *
     * @param path   截屏图片在手机端的保存位置： eg /sdcard/screen.png
     * @param series 执行机的序列号
     */
    public AbstractADB screen(String path, String series) {
        exeadb("shell screencap -p " + path, series);
        return this;
    }

    /**
     * 从远程端的指定路径copy文件到本地
     *
     * @param remotepath 设备端的文件地址
     * @param localpath  本地电脑的地址
     */
    public AbstractADB pull(String remotepath, String localpath, String series) {
        exeadb("shell pull " + remotepath + " " + localpath, series);
        return this;
    }

    public AbstractADB install(String path, String series) {
        exeadb("install " + path, series);
        return this;
    }

    /**
     * 指定cmd命令
     *
     * @param cmd cmd命令,eg: dumpsys window policy | find "mIsShowing"
     *            注意不要带 adb shell
     * @return 执行cmd命令后，输出的信息
     */
    public String execmd(String cmd) {
        String output = null;
        try {
            log.info("cmd命令:" + cmd);
            Process process = Runtime.getRuntime().exec("cmd.exe /c" + cmd);
            int status = process.waitFor();
            InputStream in = process.getInputStream();
            InputStream errorStream = process.getErrorStream();
            if (status == -1) throw new Exception(this.inputStream2str(errorStream));
            output = inputStream2str(in);
            log.info("输出结果:" + output);
        } catch (Exception e) {
            log.error(e.getStackTrace().toString());
        }

        return output;
    }

    /**
     * 执行adb 命令
     *
     * @param adbcmd cmd命令,eg: dumpsys window policy | find "mIsShowing"
     * @param series 执行机的序列，如果只有一台执行机可以传null
     * @return
     */
    public String exeadb(String adbcmd, String series) {
        String cmd = null;
        if (series == null) {
            cmd = "adb " + adbcmd;
        } else {
            cmd = String.format("adb -s %s %s", series, adbcmd);
        }
        return execmd(cmd);
    }

    /**
     * 获取cpu信息
     *
     * @param series
     * @return
     */
    public String get_cpu_info(String series) {
        String cpuinfo = exeadb("shell cat /proc/cpuinfo", series);
        return cpuinfo;
    }

    /**
     * 获取内存信息
     *
     * @param series
     * @return
     */
    public String get_meminfo(String series) {
        String meminfo = exeadb("shell cat /proc/meminfo", series);
        return meminfo;
    }

    private String inputStream2str(InputStream inputStream) throws IOException {
        List<String> lines = new ArrayList<>();
        BufferedReader reader = new BufferedReader(new InputStreamReader(inputStream));
        ;
        String line = reader.readLine();
        while (line != null) {
            lines.add(line);
            line = reader.readLine();
        }
        return String.join("\n", lines);
    }

}
